#pragma once

#include "land_base.h"
#include "land_math.h"

#include "land_graphics_conf.h"


enum {
    LAND_GRAPHICS_TFLOAT,
    LAND_GRAPHICS_INT,
    LAND_GRAPHICS_TUNSIGNED,
    LAND_GRAPHICS_TVECTOR,
    LAND_GRAPHICS_TMATRIX,
    LAND_GRAPHICS_TTEXTURE,
    LAND_GRAPHICS_TCANVAS,
};

typedef enum {
    LAND_DRAW_POINTS,
    LAND_DRAW_LINES,
    LAND_DRAW_LINE_STRIP,
    LAND_DRAW_LINE_LOOP,
    LAND_DRAW_TRIANGLES,
    LAND_DRAW_TRIANGLE_STRIP,
    LAND_DRAW_TRIANGLE_FAN,
}LandDrawType;

typedef enum {
    LAND_DEPTH_TEST_ALWAYS,
    LAND_DEPTH_TEST_NEVER,
    LAND_DEPTH_TEST_LESS,
    LAND_DEPTH_TEST_GREATER,
    LAND_DEPTH_TEST_EQUAL,
    LAND_DEPTH_TEST_NEQUAL,
    LAND_DEPTH_TEST_LEQUAL,
    LAND_DEPTH_TEST_GEQUAL,
}LandDepthTest;

typedef enum {
    LAND_COLOR_R,
    LAND_COLOR_G,
    LAND_COLOR_B,
    LAND_COLOR_A,
    LAND_COLOR_RGB,
    LAND_COLOR_RGBA,
}LandColorFormat;

typedef enum {
    LAND_TEXTURE_FILTER_LINEAR,
    LAND_TEXTURE_FILTER_NEAREST,
}LandTexFilter;

typedef enum {
    LAND_TEXTURE_WRAP_REPEAT,
    LAND_TEXTURE_WRAP_EDGE,
    LAND_TEXTURE_WRAP_BORDER,
}LandTexWrap;


#define LAND_VERTEX_OFFSET(C, B) (int)(uint64_t)(&((C *)(void*)0)->B)
typedef enum {
    LAND_VERTEX_POSITION,
    LAND_VERTEX_COLOR,
    LAND_VERTEX_UV,
    LAND_VERTEX_NORMAL,
    LAND_VERTEX_VECTOR1,
    LAND_VERTEX_VECTOR2,
    LAND_VERTEX_VECTOR3,
    LAND_VERTEX_VECTOR4,
}LandVertexLayout;

typedef enum {
    LAND_SHADER_VERTEX,
    LAND_SHADER_FRAGMENT,
}LandShaderType;

typedef enum {
    LAND_STD_SHADER_VERTEX_COLOR,
    LAND_STD_SHADER_COLOR_TEXTURE,
    LAND_STD_SHADER_APLHA_TEXTURE,
    LAND_STD_SHADER_END,
}LandStdShader;

typedef enum {
    LAND_MSAA_0,
    LAND_MSAA_4,
    LAND_MSAA_8,
    LAND_MSAA_16,
}LandMsaa;

typedef enum {
    LAND_WINDOW_EVENT_RESIZE = 1,
    LAND_WINDOW_EVENT_CLOSE,
    LAND_WINDOW_EVENT_MOUSE_MOVE,
    LAND_WINDOW_EVENT_MOUSE_DOWN,
    LAND_WINDOW_EVENT_MOUSE_UP,
    LAND_WINDOW_EVENT_KEY_DOWN,
    LAND_WINDOW_EVENT_KEY_UP,
}LandWindowEvtType;

typedef enum {
    LAND_MOUSE_LEFT,
    LAND_MOUSE_RIGHT,
    LAND_MOUSE_MIDDLE,
}LandMouseButton;

typedef struct {
    int ok;
}LandGraphics;

typedef struct LandWindow LandWindow;
typedef struct {
    int type;
    union {
        struct {
            int x;
            int y;
            int button;
        }mouse;
        struct {
            int code;
        }keyboard;
    };
}LandWindowEvent;

struct LandWindow {
    unsigned x;
    unsigned y;
    unsigned width;
    unsigned height;
    char title[256];
    LandWindow* next;
    void* ud;
    void (*onEvent)(LandWindow*, LandWindowEvent* evt);
};

typedef struct {
    LandRef ref;
    unsigned width;
    unsigned height;
    int format;
    int minFilter;
    int maxFilter;
    int sWrap;
    int tWrap;
    LandVector borderColor;
}LandTexture;

typedef struct {
    LandRef ref;
    unsigned width;
    unsigned height;
    LandVector color;
    LandMsaa msaa;
}LandCanvas;

typedef struct {
    char* data;
    size_t size;
}LandShaderSource;

typedef struct  {
    LandRef ref;
    LandShaderSource vs[LAND_MAX_SHADER_SOURCE];
    LandShaderSource fs[LAND_MAX_SHADER_SOURCE];
    unsigned vsCount;
    unsigned fsCount;
}LandShader;

typedef union {
    struct {
        LandVector position;
        LandVector uv;
        LandVector color;
        LandVector normal;
    };
    LandFloat B[16];
}LandPoint;

typedef struct  {
    LandRef ref;
    LandList* points;
    LandList* indexs;
}LandVertex;

typedef struct {
    char name[128];
    int type;
    union {
        LandFloat f;
        LandVector v;
        LandMatrix m;
        LandTexture* tex;
        LandCanvas* canvas;
    };
}LandUniform;
typedef struct {
    unsigned count;
    unsigned offset;
    LandDrawType drawType;
    LandDepthTest depthTest;
    LandVertex* vertex;
    LandShader* shader;
    LandUniform uniforms[LAND_MAX_UNIFORM];
    unsigned uniformCount;
    LandMatrix* projection;
    LandMatrix* view;
    LandMatrix* transform;
}LandDraw;

typedef struct {
    LandTexture* texture;
    int x, y;
    int fw, fh;
    int width, height;
    LandVector uv;
}LandGlyph;
typedef struct LandFont LandFont;

typedef struct {
    LandFloat width;
    LandFloat height;
    LandVector rect;
    LandVector border;
    LandVector uv;
    LandTexture* texture;
} LandFrameSlot;
typedef struct LandFrame LandFrame;

typedef struct {
    size_t(*sizeofCanvas)();
    int (*newCanvas)(LandCanvas* canvas);
    void (*freeCanvas)(LandCanvas* canvas);
    void (*clearCanvas)(LandCanvas* canvas);
    void (*resizeCanvas)(LandCanvas* canvas);
    void (*flushCanvas)(LandCanvas* canvas);
}LandCanvasBackend;

typedef struct {
    void (*drawPoints)(LandCanvas* canvas, LandFloat size, LandDraw* draw);
    void (*draw)(LandCanvas* canvas, LandDraw* draw);
}LandDrawBackend;

typedef struct {
    size_t(*sizeofShader)();
    int (*newShader)(LandShader* shader);
    void (*freeShader)(LandShader* shader);
    int (*compileShader)(LandShader* shader, const char** err);
}LandShaderBackend;

typedef struct {
    LandShader* (*newShader)(LandStdShader e);
    const char** (*getShaderSource)(LandStdShader e);
}LandStdBackend;

typedef struct  {
    size_t(*sizeofTexture)();
    int (*newTexture)(LandTexture* tex);
    int (*freeTexture)(LandTexture* tex);
    int (*uploadPixel)(LandTexture* tex,
        int format, unsigned rect[4], const void* data);
    void (*setFilter)(LandTexture* tex);
    void (*setWrap)(LandTexture* tex);
}LandTextureBackend;

typedef struct{
    size_t(*sizeofVertex)();
    int (*newVertex)(LandVertex* vertex, unsigned cap);
    void (*freeVertex)(LandVertex* vertex);
    void (*uploadVertex)(LandVertex* vertex);
} LandVertexBackend;

typedef struct{
    size_t(*sizeofWindow)();
    int (*openWindow)(LandWindow* window);
    int (*closeWindow)(LandWindow* window);
    int (*setParent)(LandWindow* window, LandWindow* parent);
    int (*drawCanvas)(LandWindow* window, void* canvas);
    void (*renderWindow)(LandWindow*, LandCanvas* canvas);
} LandWindowBackend;

typedef struct  {
    int (*init)(LandGraphics* config);
    int (*dispatch)();
    LandWindowBackend* window;
    LandTextureBackend* texture;
    LandShaderBackend* shader;
    LandDrawBackend* draw;
    LandCanvasBackend* canvas;
    LandVertexBackend* vertex;
    LandStdBackend* std;
}LandBackend;


LAND_GRAPHICS_API int
landInitGraphics(LandGraphics* config, LandBackend* backend);
LAND_GRAPHICS_API void
landDefaultGraphics(LandGraphics* config);
LAND_GRAPHICS_API int
landDispatchGraphics();

LAND_GRAPHICS_API LandWindow*
landOpenWindow(const char* title, unsigned rect[4]);
LAND_GRAPHICS_API int
landCloseWindow(LandWindow* window);
LAND_GRAPHICS_API void
landGetWindowSize(LandWindow* window, unsigned* w, unsigned* h);
LAND_GRAPHICS_API void
landRenderWindow(LandWindow* window, LandCanvas* canvas);
LAND_GRAPHICS_API void
landOnWindowEvent(LandWindow* window,
    void (*onEvt)(LandWindow*, LandWindowEvent*));

LAND_GRAPHICS_API LandVertex*
landNewVertex( unsigned cap);
LAND_GRAPHICS_API void
landClearVertex(LandVertex* vertex);
LAND_GRAPHICS_API void
landClearVertexCap(LandVertex* vertex);
LAND_GRAPHICS_API void
landPushVertexPoints(
    LandVertex* vertex, LandPoint* points, unsigned count);
LAND_GRAPHICS_API void
landPushVertexIndex(
    LandVertex* vertex, unsigned* indexs, unsigned count);
LAND_GRAPHICS_API void
landUploadVertex(LandVertex* vertex);
LAND_GRAPHICS_API unsigned
landPushVertexRect(LandVertex* vertex,
    LandVector* rect, LandVector* uv,
    LandVector* color, unsigned* offset, LandMatrix* transform);

LAND_GRAPHICS_API LandTexture*
landNewTexture(unsigned width, unsigned height, LandColorFormat format);
LAND_GRAPHICS_API LandTexture*
landNewPngTexture(const char* path);
LAND_GRAPHICS_API int
landUploadTexture(LandTexture* tex,
    int format, unsigned rect[4], const void* data);
LAND_GRAPHICS_API void
landTextureFilter(LandTexture* tex,
    LandTexFilter minFilter, LandTexFilter maxFilter);
LAND_GRAPHICS_API void
landTextureWrap(LandTexture* tex,
    LandTexWrap sWrap, LandTexWrap tWrap);

LAND_GRAPHICS_API void
landDrawPoints(LandCanvas* canvas, LandFloat size, LandDraw* draw);
LAND_GRAPHICS_API void
landDraw(LandCanvas* canvas, LandDraw* draw);
LAND_GRAPHICS_API void
landBeginDraw();
LAND_GRAPHICS_API unsigned
landCountDraw();
LAND_GRAPHICS_API unsigned
landRegUniformF(LandDraw* draw, const char* name, LandFloat f);
LAND_GRAPHICS_API unsigned
landRegUniformV(LandDraw* draw, const char* name, LandVector* v);
LAND_GRAPHICS_API unsigned
landRegUniformM(LandDraw* draw, const char* name, LandMatrix* m);
LAND_GRAPHICS_API unsigned
landRegUniformTex(LandDraw* draw, const char* name, LandTexture* tex);
LAND_GRAPHICS_API unsigned
landRegUniformCanvas(LandDraw* draw, const char* name, LandCanvas* canvas);
LAND_GRAPHICS_API void
landUniformF(LandDraw* draw, unsigned index, LandFloat f);
LAND_GRAPHICS_API void
landUniformV(LandDraw* draw, unsigned index, LandVector* v);
LAND_GRAPHICS_API void
landUniformM(LandDraw* draw, unsigned index, LandMatrix* m);
LAND_GRAPHICS_API void
landUniformTex(LandDraw* draw, unsigned index, LandTexture* tex);
LAND_GRAPHICS_API void
landUniformCanvas(LandDraw* draw, unsigned index, LandCanvas* canvas);

LAND_GRAPHICS_API LandShader*
landNewShader();
LAND_GRAPHICS_API int
landShaderSource(LandShader* shader,
    LandShaderType type, const char* data, size_t size);
LAND_GRAPHICS_API int
landCompileShader(LandShader* shader, const char** err);

LAND_GRAPHICS_API LandCanvas*
landNewCanvas(unsigned width, unsigned height, LandMsaa msaa);
LAND_GRAPHICS_API void
landCanvasSize(LandCanvas* canvas, unsigned width, unsigned height);
LAND_GRAPHICS_API void
landCanvasColor(LandCanvas* canvas, LandVector* color);
LAND_GRAPHICS_API void
landClearCanvas(LandCanvas* canvas);
LAND_GRAPHICS_API void
landFlushCanvas(LandCanvas* canvas);

LAND_GRAPHICS_API LandShader*
landNewStdShader(LandStdShader e);

LAND_GRAPHICS_API LandFont*
landNewFont(const char* file);
LAND_GRAPHICS_API LandFont*
landNewFontByData(const char* data, size_t size);
LAND_GRAPHICS_API int
landRegFont(LandFont* font,
    uint32_t ch, unsigned fsize, LandGlyph* glyph);
LAND_GRAPHICS_API unsigned
landGetFontHeight(LandFont* font);
LAND_GRAPHICS_API LandTexture*
landGetFontTexture(LandFont* font);
LAND_GRAPHICS_API void
landClearFont(LandFont* font);
LAND_GRAPHICS_API void
landClearFontCap(LandFont* font);
LAND_GRAPHICS_API uint32_t
landUtf8(const unsigned char* p, unsigned* step);

LAND_GRAPHICS_API LandFrame*
landNewFrame(LandTexture* texture, unsigned cap);
LAND_GRAPHICS_API unsigned
landRegFrameSlot(LandFrame* frame, LandFloat width,
    LandFloat height, LandVector* rect, LandVector* border);
LAND_GRAPHICS_API LandFrameSlot*
landGetFrameSlot(LandFrame* frame, unsigned index);

